﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using WorkThreading;
using digit.Core;
using SMS.RoamSMPP.Smpp;
using SMS.RoamSMPP.SmppPdu;
using SMS.Gateway.Libs;
using SMS.ServiceManager;

namespace SMS.Gateway
{
    public partial class Gateway : Form
    {
        public WorkQueue workMsgIn;
        public WorkQueue workMsgOut;

        public int[] statsMsgIn;
        public int[] statsMsgOut;

        public DateTime nextRefreshTime;
        public TimeSpan refreshInterval;

        SqlConnection SqlConn = new SqlConnection();

        private SmppConnection SMPPClient =  new SmppConnection();

        /// <summary>
        /// Load all default value for this application
        /// </summary>
        public Gateway()
        {
            ConfigSettings.LoadConfig();

            this.InitializeComponent();

            lblPartnerIP.Text = Util.GetAppSettings("PartnerIP").ToString();
            lblMyIP.Text = Util.GetAppSettings("MyIP").ToString();

            this.nextRefreshTime = DateTime.Now;
            this.refreshInterval = TimeSpan.FromSeconds(0.3);
            this.timerMsgOut.Interval = ConfigApp.ReLoadMsgOut;
            
            this.statsMsgIn = new int[6];
            this.statsMsgOut = new int[6];

            // MsgIn threading
            this.workMsgIn = new WorkQueue();
            
            ((WorkThreadPool)this.workMsgIn.WorkerPool).MaxThreads = ConfigApp.maxThread;
            ((WorkThreadPool)this.workMsgIn.WorkerPool).MinThreads = ConfigApp.minThread;
            
            this.workMsgIn.ConcurrentLimit = ConfigApp.ConcurrentLimit;
            this.workMsgIn.WorkerException += new ResourceExceptionEventHandler(this.workMsgIn_WorkerException);
            this.workMsgIn.ChangedWorkItemState += new ChangedWorkItemStateEventHandler(this.workMsgIn_ChangedWorkItemState);
            this.workMsgIn.FailedWorkItem += new WorkItemEventHandler(this.workMsgIn_FailedWorkItem);
            this.workMsgIn.AllWorkCompleted += new EventHandler(this.workMsgIn_AllWorkCompleted);
            
            // MsgOut threading
            this.workMsgOut = new WorkQueue();

            ((WorkThreadPool)this.workMsgOut.WorkerPool).MaxThreads = ConfigApp.maxThread;
            ((WorkThreadPool)this.workMsgOut.WorkerPool).MinThreads = ConfigApp.minThread;
            
            this.workMsgOut.ConcurrentLimit = ConfigApp.ConcurrentLimit;
            this.workMsgOut.WorkerException += new ResourceExceptionEventHandler(this.workMsgOut_WorkerException);
            this.workMsgOut.ChangedWorkItemState += new ChangedWorkItemStateEventHandler(this.workMsgOut_ChangedWorkItemState);
            this.workMsgOut.FailedWorkItem += new WorkItemEventHandler(this.workMsgOut_FailedWorkItem);
            this.workMsgOut.AllWorkCompleted += new EventHandler(this.workMsgOut_AllWorkCompleted);

            // SMPP Handler
            this.SMPPClient.OnDeliverSmReq += new SmppDeliverSmHandler(this.SMPPClient_OnDeliverSmReq);
            this.SMPPClient.OnUnBindReq += new SmppUnBindHandler(this.SMPPClient_OnUnBindReq);
            this.SMPPClient.OnEnquireLinkReq += new SmppEnquireLinkHandler(this.SMPPClient_OnEnquireLinkReq);
        }

        private void Gateway_Load(object sender, EventArgs e)
        {
            try
            {
                this.timerMonitor.Interval = int.Parse(this.txtTimeRestart.Text);
            }
            catch { this.timerMonitor.Interval = 300000; }

            this.timerMonitor.Stop();
            this.timerReBind.Stop();
            this.workMsgOut.Pause();
            this.Text = this.Text + " - " + Util.GetAppSettings("Version");

            //#region Start
            //if (DateTime.Now.Year <= 2020)
            //{
            //    if (!AppStatus.IsDBConnect)
            //    {
            //        this.SqlConn = new SqlConnection(ConfigApp.ConnStr);
            //        try
            //        {
            //            this.SqlConn.Open();
            //            AppStatus.IsDBConnect = true;
            //            this.ResendMsgInOut();
            //        }
            //        catch
            //        {
            //            this.WriteLog("Cannot connect to Database");
            //            return;
            //        }
            //    }
            //    try
            //    {
            //        if (this.btnStart.Text.ToLower() == "start")
            //        {
            //            if (ConfigSMPP.ConnectionMode.Value == 0)
            //            {
            //                MessageBox.Show("You need config your configuration before connecting.");
            //            }
            //            else
            //            {
            //                this.SMPPClient.Settings.ConnectionMode = ConfigSMPP.ConnectionMode;
            //                this.SMPPClient.Settings.RemoteHost = ConfigSMPP.RemoteHost;
            //                this.SMPPClient.Settings.RemotePort = ConfigSMPP.RemotePort;
            //                this.SMPPClient.Settings.BindParams.AddressNpi = 1;
            //                this.SMPPClient.Settings.BindParams.AddressTon = 1;
            //                this.SMPPClient.Settings.BindParams.AddressRange = ConfigSMPP.AddressRange;
            //                this.SMPPClient.Settings.BindParams.Password = ConfigSMPP.Password;
            //                this.SMPPClient.Settings.BindParams.SystemId = ConfigSMPP.SystemId;
            //                this.SMPPClient.Settings.BindParams.SystemType = ConfigSMPP.SystemType;
            //                this.SMPPClient.Settings.BindParams.InterfaceVersion = 0x34;
            //                SmppBindRes res = this.SMPPClient.Bind();

            //                if (res.Header.CommandStatus == 0)
            //                {
            //                    AppStatus.IsBind = true;
            //                    AppStatus.IsConnect = true;
            //                    this.workMsgOut.Resume();
            //                    this.WriteLog("Connect SMSC successfully at " + DateTime.Now.ToString());
            //                    this.lblStatus.ForeColor = Color.Blue;
            //                    this.lblStatus.Text = "Connected";
            //                    this.btnStart.Text = "Stop";
            //                    this.timerMsgOut.Start();
            //                }
            //                else
            //                {
            //                    this.WriteLog("Cannot connect to SMSC at " + DateTime.Now.ToString() + ".\r\nError Code: " + res.Header.CommandStatus.ToString() + " Description: " + SmppStatusCodes.GetDescription(res.Header.CommandStatus) + "\r\n");
            //                }
            //            }
            //        }
            //        else
            //        {
            //            AppStatus.IsBind = false;

            //            if (this.SqlConn.State == ConnectionState.Open)
            //                this.SqlConn.Close();

            //            AppStatus.IsDBConnect = false;
            //            this.SMPPClient.UnBind();
            //            this.timerMsgOut.Stop();
            //        }
            //    }
            //    catch (Exception ex)
            //    {
            //        this.WriteLog(ex.Message);
            //    }
            //}

            //this.timerReBind.Start();
            //#endregion Start
        }

        private void Gateway_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide();
            }
        }

        private void LoadMsgOutQueue()
        {
            if (this.SMPPClient.Connected)
            {
                if (this.SqlConn.State == ConnectionState.Closed)
                {
                    try
                    {
                        this.SqlConn.Open();
                    }
                    catch
                    {
                        this.WriteLog("Cannot connect to SMSC at " + DateTime.Now.ToString());
                        return;
                    }
                }

                this.timerMsgOut.Stop();
                DataTable dt = null;
                try
                {
                    dt = MessageOutManager.GetMsgOut();
                }
                catch (Exception ex)
                {
                    this.WriteLog(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss") + " Load MsgOut Error: " + ex.Message);
                    this.timerMsgOut.Start();
                    return;
                }

                if (dt != null && dt.Rows.Count > 0)
                {
                    lock (this.workMsgOut)
                    {
                        for (int i = 0; i < dt.Rows.Count; i++)
                        {
                            try
                            {
                                int msgOutId = Convert.ToInt32(dt.Rows[i]["MsgOutID"]);
                                string userId = dt.Rows[i]["MobileNo"].ToString();
                                string serviceId = dt.Rows[i]["ServiceID"].ToString();
                                string messageInfo = dt.Rows[i]["MsgOutContent"].ToString();
                                int contentType = Convert.ToInt32(dt.Rows[i]["ContentType"]);
                                this.workMsgOut.Add(new MsgOutWorkItem(msgOutId, userId, serviceId, messageInfo, contentType, this));
                            }
                            catch (Exception ex1)
                            {
                                this.WriteLog("Add MsgOut Queue Error: " + ex1.Message);
                            }
                        }
                    }
                }
                this.timerMsgOut.Start();
            }
        }

        private void AddMsgInWorkItem(SmppDeliverSmReq MsgIn)
        {
            if (MsgIn.Body.ShortMessage.ToString().IndexOf("stat:") == -1)
            {
                lock (this.workMsgIn)
                {
                    this.workMsgIn.Add(new MsgInWorkItem(MsgIn, this));
                }

                if (ConfigApp.bLogMsgIn)
                    this.WriteLog("Receive MsgIn - RequestID=" + MsgIn.Header.SequenceNumber.ToString() + " from " + MsgIn.Body.SourceAddress + " to " + MsgIn.Body.DestinationAddress + " Content: " + MsgIn.Body.ShortMessage.ToString());
            }
            else if (ConfigApp.bLogMsgIn)
            {
                this.WriteLog(string.Concat(new object[] { "Receive Dev - CommandStatus=", MsgIn.Header.CommandStatus, " RequestID", MsgIn.Header.SequenceNumber.ToString(), " from ", MsgIn.Body.SourceAddress, " to ", MsgIn.Body.DestinationAddress, " Content: ", MsgIn.Body.ShortMessage.ToString() }));
            }
        }

        #region SMPP Handler

        private void SMPPClient_OnDeliverSmReq(object sender, SmppDeliverSmEventArgs e)
        {
            if (this.InvokeRequired)
                this.Invoke(new SmppDeliverSmHandler(this.SMPPClient_OnDeliverSmReq), new object[] { sender, e });

            else
                this.AddMsgInWorkItem(e.Pdu);
        }

        private void SMPPClient_OnEnquireLinkReq(object sender, SmppEnquireLinkEventArgs e)
        {
            if (ConfigApp.bLogEn)
                this.WriteLog("EnquireLink response RequestID: " + e.Pdu.Header.SequenceNumber.ToString());
        }

        private void SMPPClient_OnUnBindReq(object sender, SmppUnBindEventArgs e)
        {
            this.lblStatus.ForeColor = Color.Red;
            this.btnStart.Text = "Start";
            this.lblStatus.Text = "Stopped";
            this.WriteLog("Disconnected SMSC at " + DateTime.Now.ToString());
            AppStatus.IsConnect = false;
            AppStatus.IsBind = false;
            this.workMsgOut.Pause();
        }

        #endregion SMPP Handler

        #region Work MsgIn

        private void workMsgIn_FailedWorkItem(object sender, WorkItemEventArgs e)
        {
            if (ConfigApp.bLogMsgIn)
            {
                this.WriteLog("MsgIn WorkQueue Error: " + e.WorkItem.FailedException.Message);
            }
        }

        private void workMsgIn_WorkerException(object sender, ResourceExceptionEventArgs e)
        {
            this.WriteLog(e.Exception.Message);
        }

        private void workMsgIn_ChangedWorkItemState(object sender, ChangedWorkItemStateEventArgs e)
        {
            try
            {
                lock (this)
                {
                    if (e.PreviousState != WorkItemState.Failing)
                    {
                        IntPtr ptr;
                        this.statsMsgIn[(int)(ptr = (IntPtr)e.PreviousState)] = this.statsMsgIn[(int)ptr] - 1;
                    }
                    if (e.PreviousState != WorkItemState.Failing)
                    {
                        IntPtr ptr2;
                        this.statsMsgIn[(int)(ptr2 = (IntPtr)e.WorkItem.State)] = this.statsMsgIn[(int)ptr2] + 1;
                    }
                }
                if (DateTime.Now > this.nextRefreshTime)
                {
                    this.CountMsgIn();
                    this.nextRefreshTime = DateTime.Now + this.refreshInterval;
                }
            }
            catch { }
        }

        private void workMsgIn_AllWorkCompleted(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(this.workMsgIn_AllWorkCompleted), new object[] { sender, e });
            }
            else
            {
                lock (this.statsMsgIn)
                {
                    this.statsMsgIn = new int[6];
                }
                this.RefreshMsgInCount();
            }
        }

        #endregion Work MsgIn

        #region Work MsgOut

        private void workMsgOut_FailedWorkItem(object sender, WorkItemEventArgs e)
        {
            if (ConfigApp.bLogMsgOut)
            {
                this.WriteLog("MsgOutWorkQueue Error: " + e.WorkItem.FailedException.Message);
            }
        }

        private void workMsgOut_WorkerException(object sender, ResourceExceptionEventArgs e)
        {
            this.WriteLog(e.Exception.Message);
        }

        private void workMsgOut_ChangedWorkItemState(object sender, ChangedWorkItemStateEventArgs e)
        {
            lock (this.statsMsgOut)
            {
                if (e.PreviousState != WorkItemState.Failing)
                {
                    IntPtr ptr;
                    this.statsMsgOut[(int)(ptr = (IntPtr)e.PreviousState)] = this.statsMsgOut[(int)ptr] - 1;
                }
                if (e.PreviousState != WorkItemState.Failing)
                {
                    IntPtr ptr2;
                    this.statsMsgOut[(int)(ptr2 = (IntPtr)e.WorkItem.State)] = this.statsMsgOut[(int)ptr2] + 1;
                }
            }
            if (DateTime.Now > this.nextRefreshTime)
            {
                this.RefreshMsgOutCount();
                this.nextRefreshTime = DateTime.Now + this.refreshInterval;
            }
        }

        private void workMsgOut_AllWorkCompleted(object sender, EventArgs e)
        {
            try
            {
                if (this.InvokeRequired)
                    this.Invoke(new EventHandler(this.workMsgOut_AllWorkCompleted), new object[] { sender, e });
                
                else
                {
                    lock (this.statsMsgOut)
                    {
                        this.statsMsgOut = new int[6];
                    }
                    this.RefreshMsgInCount();
                }
            }
            catch { }
        }

        #endregion Work MsgOut

        /// <summary>
        /// Reload MsgOut count and fill label
        /// </summary>
        private void RefreshMsgOutCount()
        {
            if (this.InvokeRequired)
            {
                MethodInvoker mi = new MethodInvoker(RefreshMsgOutCount);
                this.BeginInvoke(mi);
            }
            else
            {
                lock (this.lblMTSuccess)
                {
                    this.lblMTSuccess.Text = this.statsMsgOut[5].ToString("N0");
                }
                lock (this.lblMTError)
                {
                    this.lblMTError.Text = this.statsMsgOut[4].ToString("N0");
                }
                lock (this.lblMTRunning)
                {
                    this.lblMTRunning.Text = this.statsMsgOut[3].ToString("N0");
                }
                lock (this.lblMTQueue)
                {
                    this.lblMTQueue.Text = this.statsMsgOut[2].ToString("N0");
                }
                lock (this.lblMTSchedule)
                {
                    this.lblMTSchedule.Text = this.statsMsgOut[1].ToString("N0");
                }
            }
        }

        /// <summary>
        /// Reload MsgIn count and fill label
        /// </summary>
        private void RefreshMsgInCount()
        {
            if (this.InvokeRequired)
            {
                MethodInvoker mi = new MethodInvoker(RefreshMsgInCount);
                this.BeginInvoke(mi);
            }
            else
            {
                lock (this.lblMOSuccess)
                {
                    this.lblMOSuccess.Text = this.statsMsgIn[5].ToString("N0");
                }
                lock (this.lblMOError)
                {
                    this.lblMOError.Text = this.statsMsgIn[4].ToString("N0");
                }
                lock (this.lblMORunning)
                {
                    this.lblMORunning.Text = this.statsMsgIn[3].ToString("N0");
                }
                lock (this.lblMOQueue)
                {
                    this.lblMOQueue.Text = this.statsMsgIn[2].ToString("N0");
                }
                lock (this.lblMOSchedule)
                {
                    this.lblMOSchedule.Text = this.statsMsgIn[1].ToString("N0");
                }
            }
        }

        /// <summary>
        /// Write message to textbox
        /// </summary>
        /// <param name="msg"></param>
        public void WriteLog(string msg)
        {
            lock (this.txtLog)
            {
                if ((this.txtLog.TextLength + msg.Length) > 0x8000)
                {
                    this.txtLog.Clear();
                }
                this.txtLog.AppendText(msg + Environment.NewLine);
                this.txtLog.ScrollToCaret();
            }
        }

        /// <summary>
        /// Exit application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExit_Click(object sender, EventArgs e)
        {
            this.SqlConn.Close();
            this.SmppClient.UnBind();
            this.timerReBind.Stop();
            this.timerMsgOut.Stop();
            this.Close();
        }

        /// <summary>
        /// Start connect to SMPP and Database
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            this.timerMonitor.Start();
            if (this.chkSetMonitor.Checked) this.txtTimeRestart.Enabled = false;
            else
                this.txtTimeRestart.Enabled = false;

            if (DateTime.Now.Year <= 2020)
            {
                if (!AppStatus.IsDBConnect)
                {
                    this.SqlConn = new SqlConnection(ConfigApp.ConnStr);
                    try
                    {
                        this.SqlConn.Open();
                        AppStatus.IsDBConnect = true;
                        this.ResendMsgInOut();
                    }
                    catch
                    {
                        this.WriteLog("Cannot connect to Database");
                        return;
                    }
                }
                try
                {
                    if (this.btnStart.Text.ToLower() == "start")
                    {
                        if (ConfigSMPP.ConnectionMode.Value == 0)
                        {
                            MessageBox.Show("You need config your configuration before connecting.");
                        }
                        else
                        {
                            this.SMPPClient.Settings.ConnectionMode = ConfigSMPP.ConnectionMode;
                            this.SMPPClient.Settings.RemoteHost = ConfigSMPP.RemoteHost;
                            this.SMPPClient.Settings.RemotePort = ConfigSMPP.RemotePort;
                            this.SMPPClient.Settings.BindParams.AddressNpi = 1;
                            this.SMPPClient.Settings.BindParams.AddressTon = 1;
                            this.SMPPClient.Settings.BindParams.AddressRange = ConfigSMPP.AddressRange;
                            this.SMPPClient.Settings.BindParams.Password = ConfigSMPP.Password;
                            this.SMPPClient.Settings.BindParams.SystemId = ConfigSMPP.SystemId;
                            this.SMPPClient.Settings.BindParams.SystemType = ConfigSMPP.SystemType;
                            this.SMPPClient.Settings.BindParams.InterfaceVersion = 0x34;
                            SmppBindRes res = this.SMPPClient.Bind();

                            if (res.Header.CommandStatus == 0)
                            {
                                AppStatus.IsBind = true;
                                AppStatus.IsConnect = true;
                                this.workMsgOut.Resume();
                                this.WriteLog("Connect SMSC successfully at " + DateTime.Now.ToString());
                                this.lblStatus.ForeColor = Color.Blue;
                                this.lblStatus.Text = "Connected";
                                this.btnStart.Text = "Stop";
                                this.timerMsgOut.Start();
                            }
                            else
                            {
                                this.WriteLog("Cannot connect to SMSC at " + DateTime.Now.ToString() + ".\r\nError Code: " + res.Header.CommandStatus.ToString() + " Description: " + SmppStatusCodes.GetDescription(res.Header.CommandStatus) + "\r\n");
                            }
                        }
                    }
                    else
                    {
                        AppStatus.IsBind = false;

                        if (this.SqlConn.State == ConnectionState.Open)
                            this.SqlConn.Close();

                        AppStatus.IsDBConnect = false;                        
                        this.SMPPClient.UnBind();
                        this.timerMsgOut.Stop();
                    }
                }
                catch (Exception ex)
                {
                    this.WriteLog(ex.Message);
                }
            }

            this.timerReBind.Start();
        }

        /// <summary>
        /// Counting MsgIn and fill to label
        /// </summary>
        private void CountMsgIn()
        {
            try
            {
                if (this.InvokeRequired)
                {
                    MethodInvoker method = new MethodInvoker(this.CountMsgIn);
                    this.BeginInvoke(method);
                }
                else
                {
                    lock (this)
                    {
                        this.lblMOSchedule.Text = this.statsMsgIn[1].ToString("N0");
                        this.lblMOQueue.Text = this.statsMsgIn[2].ToString("N0");
                        this.lblMORunning.Text = this.statsMsgIn[3].ToString("N0");
                        this.lblMOError.Text = this.statsMsgIn[4].ToString("N0");
                        this.lblMOSuccess.Text = this.statsMsgIn[5].ToString("N0");
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// Counting MsgOut and fill to label
        /// </summary>
        private void CountMsgOut()
        {
            try
            {
                if (this.InvokeRequired)
                {
                    MethodInvoker method = new MethodInvoker(this.CountMsgOut);
                    this.BeginInvoke(method);
                }
                else
                {
                    lock (this)
                    {
                        this.lblMTSchedule.Text = this.statsMsgOut[1].ToString("N0");
                        this.lblMTQueue.Text = this.statsMsgOut[2].ToString("N0");
                        this.lblMTRunning.Text = this.statsMsgOut[3].ToString("N0");
                        this.lblMTError.Text = this.statsMsgOut[4].ToString("N0");
                        this.lblMTSuccess.Text = this.statsMsgOut[5].ToString("N0");
                    }
                }
            }
            catch { }
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            lock (this.txtLog)
            {
                this.txtLog.Text = "";
            }

            try
            {
                // Reset MO
                lock (this.statsMsgIn)
                {
                    for (int i = 0; i < this.statsMsgIn.Length; i++)
                    {
                        this.statsMsgIn[i] = 0;
                    }
                }

                txtTotalMO.Text = "0";
                this.CountMsgIn();

                // Reset MT
                lock (this.statsMsgOut)
                {
                    for (int i = 0; i < this.statsMsgOut.Length; i++)
                    {
                        this.statsMsgOut[i] = 0;
                    }
                }

                txtTotalMT.Text = "0";
                this.CountMsgOut();
            }
            catch { }
        }

        private void EnquireLinkReq()
        {
            this.timerEN.Stop();
            try
            {
                SmppEnquireLinkRes res;
                lock (this.SMPPClient)
                {
                    res = this.SMPPClient.EnquireLinkSm();
                }
                if (res.Header.CommandStatus == 0)
                {
                    if (ConfigApp.bLogEn)
                        this.WriteLog("Send EnquireLink SeqID " + res.Header.SequenceNumber);
                }
                else
                {
                    if (ConfigApp.bLogEn)
                        this.WriteLog("Send EnquireLink SeqID " + res.Header.SequenceNumber + " Error");

                    if (AppStatus.IsBind)
                    {
                        DateTime now = DateTime.Now;
                        this.SMPPClient.UnBind();

                        while (!AppStatus.IsConnect)
                        {
                            if (DateTime.Now > now)
                            {
                                this.ReBin();
                                now = now.AddSeconds(3.0);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (ConfigApp.bLogEn)
                    this.WriteLog("Send EnquireLink Error: " + ex.Message);

                if (AppStatus.IsBind)
                {
                    DateTime time2 = DateTime.Now;
                    this.SMPPClient.UnBind();
                    while (!AppStatus.IsConnect)
                    {
                        if (DateTime.Now > time2)
                        {
                            this.ReBin();
                            time2 = time2.AddSeconds(3.0);
                        }
                    }
                }
            }
            this.timerEN.Start();
        }

        /// <summary>
        /// Load MsgOut for send
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerMT_Tick(object sender, EventArgs e)
        {
            this.LoadMsgOutQueue();
        }

        private void timerEN_Tick(object sender, EventArgs e)
        {

        }

        private void timerMonitor_Tick(object sender, EventArgs e)
        {
            if (this.chkSetMonitor.Checked)
            {
                AppStatus.IsBind = false;

                if (this.SqlConn.State == ConnectionState.Open)
                    this.SqlConn.Close();

                AppStatus.IsDBConnect = false;
                this.SMPPClient.UnBind();
                this.timerMsgOut.Stop();
                this.timerReBind.Start();
            }
        }

        /// <summary>
        /// ReBind SMPP connection
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerReBind_Tick(object sender, EventArgs e)
        {
            if (!AppStatus.IsConnect)
            {
                if (AppStatus.IsBind)
                {
                    this.SMPPClient.UnBind();
                }
                this.ReBin();
            }
        }

        /// <summary>
        /// Enquire Link
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkEnquireLink_CheckedChanged(object sender, EventArgs e)
        {
            ConfigApp.bLogEn = this.chkEnquireLink.Checked;
        }

        /// <summary>
        /// Test connection over send sms
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            new SendSms(this).Show();
        }

        /// <summary>
        /// Enable / Disable write Incoming SMS
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkLogMO_CheckedChanged(object sender, EventArgs e)
        {
            ConfigApp.bLogMsgIn = this.chkLogMO.Checked;
        }

        /// <summary>
        /// Enable / Disable write log Outgoing SMS
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkLogMT_CheckedChanged(object sender, EventArgs e)
        {
            ConfigApp.bLogMsgOut = this.chkLogMT.Checked;
        }

        /// <summary>
        /// Resend MsgIn / MsgOut when reconnect SMPP
        /// </summary>
        private void ResendMsgInOut()
        {
            try
            {
                bool result = false;
                result = MessageOutManager.Update_MsgInOut_Loading();
            }
            catch { }
        }

        /// <summary>
        /// Reconnect to SMSC
        /// </summary>
        private void ReBin()
        {
            try
            {
                if (DateTime.Now.Year <= 2020)
                {
                    this.SMPPClient.Settings.ConnectionMode = ConfigSMPP.ConnectionMode;
                    this.SMPPClient.Settings.RemoteHost = ConfigSMPP.RemoteHost;
                    this.SMPPClient.Settings.RemotePort = ConfigSMPP.RemotePort;
                    this.SMPPClient.Settings.BindParams.AddressNpi = 1;
                    this.SMPPClient.Settings.BindParams.AddressTon = 1;
                    this.SMPPClient.Settings.BindParams.AddressRange = ConfigSMPP.AddressRange;
                    this.SMPPClient.Settings.BindParams.Password = ConfigSMPP.Password;
                    this.SMPPClient.Settings.BindParams.SystemId = ConfigSMPP.SystemId;
                    this.SMPPClient.Settings.BindParams.SystemType = ConfigSMPP.SystemType;
                    this.SMPPClient.Settings.BindParams.InterfaceVersion = 0x34;
                    SmppBindRes res = this.SMPPClient.Bind();

                    if (res.Header.CommandStatus == 0)
                    {
                        AppStatus.IsConnect = true;
                        AppStatus.IsBind = true;
                        this.workMsgOut.Resume();                        
                        this.WriteLog("Reconnect to SMSC successfully at " + DateTime.Now.ToShortTimeString());
                        this.lblStatus.ForeColor = Color.Blue;
                        this.lblStatus.Text = "Connected";
                        this.btnStart.Text = "Stop";

                        // Resend all msgin and msgout just send fail
                        this.ResendMsgInOut();

                        this.timerMsgOut.Start();
                    }
                    else
                    {
                        this.WriteLog("Reconnect to SMSC failed at " + DateTime.Now.ToString() + ".\r\nError Code: " + res.Header.CommandStatus.ToString() + " Description: " + this.SMPPClient.LastException.Message + "\r\n");
                    }
                }
            }
            catch (Exception ex)
            {
                this.WriteLog(ex.Message);
            }
        }

        /// <summary>
        /// Submit SMS to SMSC over SMPP
        /// </summary>
        /// <param name="SubmitMsgOut"></param>
        /// <returns></returns>
        public SmppSubmitSmRes SubmitSm(SmppSubmitSmReq SubmitMsgOut)
        {
            lock (this.SMPPClient)
            {
                return this.SMPPClient.SubmitSm(SubmitMsgOut);
            }
        }

        // Properties
        public WorkQueue MsgOutWorkQueue
        {
            get { return this.workMsgOut; }
        }

        public SmppConnection SmppClient
        {
            get { return this.SMPPClient; }
        }
    }
}